package com.rickpan.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * Redis配置类
 * 
 * @author RickPan Team
 * @version 1.0.0
 */
@Configuration
@EnableCaching
public class RedisConfig {

    /**
     * 配置RedisTemplate
     * 
     * @param connectionFactory Redis连接工厂
     * @return RedisTemplate实例
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 配置JSON序列化器
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = createJacksonSerializer();

        // 配置字符串序列化器
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 设置key和hashKey的序列化器
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);

        // 设置value和hashValue的序列化器
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        // 启用默认序列化器
        template.setDefaultSerializer(jackson2JsonRedisSerializer);
        template.setEnableDefaultSerializer(true);

        template.afterPropertiesSet();
        return template;
    }

    /**
     * 配置缓存管理器
     * 
     * @param connectionFactory Redis连接工厂
     * @return CacheManager实例
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        // 创建JSON序列化器
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = createJacksonSerializer();

        // 配置序列化对
        RedisSerializationContext.SerializationPair<Object> pair = 
            RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);

        // 默认缓存配置
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(pair)
                .entryTtl(Duration.ofHours(1)) // 默认1小时过期
                .disableCachingNullValues(); // 不缓存null值

        // 针对不同业务场景的缓存配置
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
        
        // 用户信息缓存 - 30分钟
        cacheConfigurations.put("users", defaultCacheConfig.entryTtl(Duration.ofMinutes(30)));
        
        // 文件信息缓存 - 1小时
        cacheConfigurations.put("files", defaultCacheConfig.entryTtl(Duration.ofHours(1)));
        
        // 文件夹信息缓存 - 2小时
        cacheConfigurations.put("folders", defaultCacheConfig.entryTtl(Duration.ofHours(2)));
        
        // 权限信息缓存 - 15分钟
        cacheConfigurations.put("permissions", defaultCacheConfig.entryTtl(Duration.ofMinutes(15)));
        
        // 文件预览缓存 - 6小时
        cacheConfigurations.put("previews", defaultCacheConfig.entryTtl(Duration.ofHours(6)));
        
        // 分享链接缓存 - 24小时
        cacheConfigurations.put("shares", defaultCacheConfig.entryTtl(Duration.ofHours(24)));
        
        // 系统配置缓存 - 12小时
        cacheConfigurations.put("configs", defaultCacheConfig.entryTtl(Duration.ofHours(12)));
        
        // JWT黑名单缓存 - 根据token过期时间
        cacheConfigurations.put("jwt-blacklist", defaultCacheConfig.entryTtl(Duration.ofHours(24)));
        
        // 验证码缓存 - 5分钟
        cacheConfigurations.put("verification-codes", defaultCacheConfig.entryTtl(Duration.ofMinutes(5)));
        
        // 登录失败次数缓存 - 30分钟
        cacheConfigurations.put("login-attempts", defaultCacheConfig.entryTtl(Duration.ofMinutes(30)));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(defaultCacheConfig)
                .withInitialCacheConfigurations(cacheConfigurations)
                .build();
    }

    /**
     * 创建Jackson序列化器
     * 
     * @return Jackson2JsonRedisSerializer实例
     */
    private Jackson2JsonRedisSerializer<Object> createJacksonSerializer() {
        ObjectMapper objectMapper = new ObjectMapper();

        // 设置可见性
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 启用默认类型
        objectMapper.activateDefaultTyping(
            LaissezFaireSubTypeValidator.instance,
            ObjectMapper.DefaultTyping.NON_FINAL
        );

        // 注册Java时间模块
        objectMapper.registerModule(new JavaTimeModule());

        // 禁用将日期写为时间戳
        objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 使用新的构造函数，直接传入ObjectMapper
        return new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
    }
}
